Breakpoints, ενέργειες, και watches#

Αυτό το κεφάλαιο καλύπτει τη διακοπή του αποσφαλματωτή σε συγκεκριμένο σημείο - μια γραμμή, μια υπορουτίνα, μια συνθήκη, μια αλλαγή τιμής - και τη μηχανική των hook προτροπής που σας επιτρέπει να τρέχετε αυτόματα κώδικα σε κάθε διακοπή.

Οι αναγνώστες που φτάνουν εδώ ξέρουν να εκκινούν το perl -d και να κάνουν βηματική εκτέλεση γραμμή προς γραμμή. Η επόμενη δεξιότητα είναι να μεταβαίνετε απευθείας στο ενδιαφέρον σημείο και να σταματάτε μόνο όταν το πρόβλημα πρόκειται να εκδηλωθεί.

Breakpoints σε γραμμές και σε sub#

Εντολή

Αποτέλεσμα

b

Breakpoint στην τρέχουσα γραμμή.

b LINE

Breakpoint στη γραμμή LINE στο τρέχον αρχείο.

b LINE COND

Υπό συνθήκη· διακοπή όταν η COND είναι αληθής.

b FILE:LINE

Μεταξύ αρχείων· το FILE ταιριάζει με εγγραφή του %INC.

b FILE:LINE COND

Υπό συνθήκη μεταξύ αρχείων.

b SUB

Διακοπή στην πρώτη γραμμή της SUB (η SUB πρέπει να είναι μεταγλωττισμένη).

b SUB COND

Breakpoint sub υπό συνθήκη.

b $coderef

Διακοπή στη sub στην οποία αναφέρεται το $coderef (δεν υποστηρίζεται COND).

b compile SUB

Διακοπή αφού τελειώσει η μεταγλώττιση της SUB, πριν τρέξει το σώμα της.

b postpone SUB

Διακοπή την πρώτη φορά που καλείται η SUB, ακόμη και αν δεν έχει φορτωθεί.

b load FILE

Διακοπή όταν το FILE γίνεται require / do.

B LINE

Διαγραφή breakpoint στη γραμμή LINE.

B *

Διαγραφή όλων των breakpoints.

disable [FILE:]LINE

Απενεργοποίηση χωρίς αφαίρεση.

enable  [FILE:]LINE

Επανενεργοποίηση.

L

Λίστα από breakpoints, ενέργειες, και watches.

L b

Λίστα μόνο από breakpoints.

Οι συνθήκες είναι σκέτες εκφράσεις, όχι if (…):

  DB<1> b 237 $count > 10
  DB<2> b 42 /unauthorized/i
  DB<3> b validate_payload ref($obj) eq 'HASH' && keys %$obj

Τα breakpoints τοποθετούνται μόνο σε γραμμές που περιέχουν εκτελέσιμο κώδικα. Μια κενή γραμμή, ένα καθαρό σχόλιο, ή η συνέχεια προηγούμενης δήλωσης απορρίπτεται:

  DB<1> b 3
Line 3 not breakable.

Μια γραμμή φέρει το πολύ ένα breakpoint και μία ενέργεια· η προσθήκη δεύτερου επανεγγράφει το πρώτο.

Πίνακας χρονισμού#

Πού στον κύκλο ζωής του προγράμματος πυροδοτείται ένα breakpoint έχει σημασία - ειδικά για κώδικα σε μπλοκ BEGIN ή αρθρώματα που γίνονται require τεμπέλικα.

Στόχος

Εντολή

Διακοπή στην πρώτη δήλωση χρόνου εκτέλεσης

Προεπιλογή - ο αποσφαλματωτής ήδη σταματάει εκεί.

Διακοπή μέσα σε μπλοκ BEGIN { }

Εισάγετε $DB::single = 1; μέσα στο μπλοκ.

Διακοπή πριν τρέξει το σώμα μιας sub (μετά τη μεταγλώττισή της)

b compile SUB

Διακοπή στην πρώτη κλήση μιας sub που δεν έχει ακόμη φορτωθεί

b postpone SUB

Διακοπή όταν ένα αρχείο γίνεται require ή do

b load /full/path/from/%INC

Διακοπή σε συγκεκριμένη γραμμή

b LINE

Διακοπή σε γραμμή μόνο όταν ισχύει μια συνθήκη

b LINE COND

Το $DB::single = 1; μέσα σε μπλοκ BEGIN είναι το κόλπο για αποσφαλμάτωση κατά τη μεταγλώττιση: η εγγραφή b στην προτροπή λειτουργεί μόνο αφού τρέχει ο αποσφαλματωτής, αλλά ο κώδικας BEGIN τρέχει πριν από την πρώτη προτροπή. Ρίξτε την ανάθεση μέσα στο μπλοκ, εκκινήστε υπό -d, και ο αποσφαλματωτής σταματάει στην επόμενη γραμμή στην οποία μπορεί να σπάσει η εκτέλεση μέσα στο μπλοκ.

Η πρόσβαση στο $DB::single όταν δεν τρέχετε υπό -d αυτο-δημιουργεί το DB:: αβλαβώς - το μοτίβο είναι ασφαλές να γίνει commit.

Παράθεση και διαχείριση breakpoints#

  DB<1> L
app.pl:
 42:   $user = User->load($id);
       break if (1)
 91:   dispatch($req);
       break if ($req->method eq 'POST')

  DB<2> disable 42
  DB<3> enable 42
  DB<4> B 42
  DB<5> B *

Τα disable / enable εναλλάσσουν ένα breakpoint χωρίς να ξεχνούν τη συνθήκη του - χρήσιμο όταν θέλετε να παρακάμψετε προσωρινά ένα «καυτό» breakpoint και να το επανοπλίσετε αργότερα.

Ενέργειες: αυτόματη εκτέλεση κώδικα σε μια γραμμή#

Μια ενέργεια τρέχει κώδικα Perl πριν εκτελεστεί η καθορισμένη γραμμή, χωρίς να σταματάει. Χρησιμοποιήστε την για παθητική παρατήρηση:

  DB<1> a 42 print "entering: user_id=$user_id\n"
  DB<2> a 91 warn "POST body:\n" . Dumper($body) if $req->method eq 'POST'
  DB<3> L a
app.pl:
 42: ...
       action: print "entering: user_id=$user_id\n"
  DB<4> A 42              # delete action at line 42
  DB<5> A *               # delete all actions

Διάταξη σε γραμμή στην οποία μπορεί να σπάσει η εκτέλεση:

  1. Ελέγχεται η συνθήκη του breakpoint.

  2. Εκτυπώνεται η έξοδος ίχνους (αν η ιχνηλάτηση είναι ενεργή).

  3. Τρέχει η ενέργεια.

  4. Εμφανίζεται η προτροπή (αν χτυπήθηκε breakpoint ή κάνετε βηματική εκτέλεση).

  5. Εκτελείται η ίδια η γραμμή.

Ενέργειες και breakpoints συνυπάρχουν στην ίδια γραμμή - το πολύ ένα από κάθε είδος.

Watches: διακοπή σε αλλαγή τιμής#

Ένα watch αναφέρει την παλιά και τη νέα τιμή όταν μια παρακολουθούμενη έκφραση αλλάζει, και σας οδηγεί στην προτροπή:

  DB<1> w $global_count
  DB<2> c
Watchpoint 0:   $global_count changed:
    old value:  42
    new value:  43
main::tick(app.pl:118):    ++$global_count;
  DB<3> W $global_count   # delete this watch
  DB<4> W *               # delete all watches

Τα watches αποτιμώνται σε κάθε γραμμή στην οποία μπορεί να σπάσει η εκτέλεση. Οι εκφράσεις πρέπει να αναφέρονται σε καθολικές ή προσβάσιμα ψευδώνυμα· οι λεξιλογικές μεταβλητές my δεν παρακολουθούνται απευθείας. Όταν μια λεξιλογική έχει σημασία, χρησιμοποιήστε το Tie::Watch στον κώδικα για να εγκαταστήσετε watcher στη στιγμή του tie, ή αναθέστε μέσω ψευδωνύμου εμβέλειας πακέτου.

Τα watches προσθέτουν κόστος ανά δήλωση ανάλογο του πλήθους των watches και του κόστους κάθε έκφρασης. Κρατήστε τα στενά και αφαιρέστε τα όταν τελειώσετε.

Hooks προτροπής: εκτέλεση κώδικα σε κάθε διακοπή#

Τα < / > εγκαθιστούν κώδικα Perl που τρέχει αυτόματα πριν / μετά από κάθε προτροπή. Τα { / {{ κάνουν το ίδιο για εντολές αποσφαλματωτή:

Εντολή

Αποτέλεσμα

< CMD

Κώδικας Perl πριν από κάθε προτροπή (= μετά τη γραμμή που μόλις εκτελέστηκε).

<< CMD

Προσάρτηση στη λίστα προ-προτροπής.

< ?

Λίστα κώδικα προ-προτροπής.

< *

Διαγραφή όλου του κώδικα προ-προτροπής.

> CMD / >> CMD

Κώδικας Perl μετά από κάθε προτροπή (= πριν από την επόμενη γραμμή).

{ DBCMD

Εντολή αποσφαλματωτή (όχι Perl) προ-προτροπής.

{{ DBCMD

Προσάρτηση στη λίστα εντολών αποσφαλματωτή προ-προτροπής.

Τυπική χρήση: χρονική σφραγίδα σε κάθε βήμα:

  DB<1> < print "stop: ", scalar localtime, "\n"
  DB<2> > print "start: ", scalar localtime, "\n"

Ή πάντα να εμφανίζεται η τρέχουσα γραμμή και μια παρακολουθούμενη μεταβλητή:

  DB<1> { v
  DB<2> { p $important

Πολλαπλών γραμμών: διαφύγετε το newline με \:

  DB<1> < for my $f (@important_files) {    \
cont:     print "  $f: ", (-s $f) // 'n/a', "\n"; \
cont: }

Ψευδώνυμα#

Μόνιμες συντομεύσεις εντολών μέσω =:

  DB<1> = len s/^len(.*)/p length($1)/
  DB<2> = quit s/^quit(\s*)/exit/
  DB<3> =                      # list all aliases

Τα ψευδώνυμα ζουν στο %DB::alias και εφαρμόζονται στη στιγμή της αποστολής. Ορίστε τα μία φορά στο .perldb για επιμονή πέρα από τη συνεδρία.

Breakpoints μίας χρήσης#

Το c LINE ορίζει breakpoint στη γραμμή LINE, συνεχίζει, και καθαρίζει το breakpoint όταν χτυπήσει:

  DB<1> c 42

Ο απλούστερος τρόπος για να πείτε «απλώς τρέξε ως τη γραμμή 42 και σταμάτα εκεί». Χωρίς χειροκίνητη ζευγαροποίηση b / B.

Διακοπή στην εισαγωγή / στην πρώτη κλήση τεμπέλικα#

Όταν μια sub ζει σε άρθρωμα που μπορεί να μην έχει ακόμη φορτωθεί, το b SUB αποτυγχάνει:

  DB<1> b MyApp::Worker::dispatch
Subroutine not yet compiled.

Το b postpone περιμένει να τελειώσει η μεταγλώττιση της sub:

  DB<1> b postpone MyApp::Worker::dispatch
  DB<2> c

Για αρχεία που φορτώνονται με require / do, το b load διακόπτει στην πρώτη φόρτωση:

  DB<1> b load /usr/share/perl5/MyApp/Worker.pm

Το όνομα αρχείου πρέπει να ταιριάζει με την πλήρη διαδρομή στο %INC, όχι μόνο με το όνομα του αρθρώματος.

Μάθετε περισσότερα#

  • inspecting-state - τι να κοιτάξετε όταν πυροδοτηθεί ένα breakpoint.

  • tracing - όταν θέλετε να παρακολουθήσετε τι συμβαίνει χωρίς διακοπή.