web-dev-qa-db-fra.com

Afficher le tableau dans LLDB: équivalent de l'opérateur '@' de GDB dans Xcode 4.1

Je voudrais voir un tableau d'éléments pointés par un pointeur. Dans GDB, cela peut être fait en traitant la mémoire pointée comme un tableau artificiel d'une longueur donnée en utilisant l'opérateur '@' comme

*pointer @ length

length est le nombre d'éléments que je souhaite visualiser.

La syntaxe ci-dessus ne fonctionne pas dans LLDB fourni avec Xcode 4.1.

Existe-t-il un moyen d'accomplir ce qui précède dans LLDB?

71
midinastasurazz

En fait, il existe un moyen simple de le faire, en convertissant le pointeur en un pointeur vers un tableau.

Par exemple, si vous avez un int* ptr, et vous voulez le voir comme un tableau de dix entiers, vous pouvez le faire

p *(int(*)[10])ptr

Parce qu'elle ne repose que sur les fonctionnalités C standard, cette méthode fonctionne sans plugins ni paramètres spéciaux. Il fonctionne également avec d'autres débogueurs comme GDB ou CDB, même s'ils ont également des syntaxes spécialisées pour l'impression des tableaux.

119
Siyuan Ren

À partir de lldb dans Xcode 8.0, il y a une nouvelle commande parray intégrée. Vous pouvez donc dire:

(lldb) parray <COUNT> <EXPRESSION>

pour imprimer la mémoire pointée par le résultat de EXPRESSION sous la forme d'un tableau d'éléments COUNT du type pointé par l'expression.

Si le nombre est stocké dans une variable disponible dans la trame actuelle, alors n'oubliez pas que vous pouvez faire:

(lldb) parray `count_variable` pointer_to_malloced_array

C'est une fonctionnalité générale de lldb, tout argument de ligne de commande dans lldb entouré de guillemets est évalué comme une expression qui renvoie un entier, puis l'entier est substitué à l'argument avant l'exécution de la commande.

29
Jim Ingham

La seule façon que j'ai trouvée était via un module de script Python:

""" File: parray.py """
import lldb
import shlex

def parray(debugger, command, result, dict):
    args = shlex.split(command)
    va = lldb.frame.FindVariable(args[0])
    for i in range(0, int(args[1])):
        print va.GetChildAtIndex(i, 0, 1)

Définissez une commande "parray" dans lldb:

(lldb) command script import /path/to/parray.py
(lldb) command script add --function parray.parray parray

Vous pouvez maintenant utiliser "parray longueur variable":

(lldb) parray a 5
(double) *a = 0
(double) [1] = 0
(double) [2] = 1.14468
(double) [3] = 2.28936
(double) [4] = 3.43404
26
Martin R

Avec Xcode 4.5.1 (qui peut ou non vous aider maintenant), vous pouvez le faire dans la console lldb:

(lldb) type summary add -s "${var[0-63]}" "float *"
(lldb) frame variable pointer
  (float *) pointer = 0x000000010ba92950 [0.0,1.0,2.0,3.0, ... ,63.0]

Cet exemple suppose que "pointeur" est un tableau de 64 flottants: float pointer[64];

15
davidA

En commençant par la réponse de Martin R, je l'ai amélioré comme suit:

  1. Si le pointeur n'est pas une simple variable, par exemple:

    struct {
      int* at;
      size_t size;
    } a;
    

    Ensuite, "parray a.at 5" échoue.

    J'ai corrigé cela en remplaçant "FindVariable" par "GetValueForVariablePath".

  2. Maintenant, que se passe-t-il si les éléments de votre tableau sont des agrégats, par exemple:

    struct {
      struct { float x; float y; }* at;
      size_t size;
    } a;
    

    Ensuite, "parray a.at 5" s'affiche: a.at-> x, a.at-> y, a.at [2], a.at [3], a.at [4] car GetChildAtIndex () renvoie des membres d'agrégats.

    J'ai résolu ce problème en résolvant "a.at" + "[" + str (i) + "]" à l'intérieur de la boucle au lieu de résoudre "a.at" puis de récupérer ses enfants.

  3. Ajout d'un "premier" argument facultatif (Usage: parray [FIRST] COUNT), qui est utile lorsque vous avez un grand nombre d'éléments.

  4. Faites-le faire le "script de commande ajouter -f parray.parray parray" à init

Voici ma version modifiée:

import lldb
import shlex

def parray(debugger, command, result, dict):
  args = shlex.split(command)
  if len(args) == 2:
    count = int(args[1])
    indices = range(count)
  Elif len(args) == 3:
    first = int(args[1]), count = int(args[2])
    indices = range(first, first + count)
  else:
    print 'Usage: parray ARRAY [FIRST] COUNT'
    return
  for i in indices:
    print lldb.frame.GetValueForVariablePath(args[0] + "[" + str(i) + "]")

def __lldb_init_module(debugger, internal_dict):
  debugger.HandleCommand('command script add -f parray.parray parray')
12
jng

Il ne semble pas encore être pris en charge.

Vous pouvez utiliser la fonction de lecture en mémoire (lecture en mémoire/x), comme

(lldb) memory read -ff -c10 `test`

pour imprimer un flotteur dix fois à partir de ce pointeur. Cela devrait être la même fonctionnalité que @ de gdb.

12
w-m

J'ai essayé d'ajouter un commentaire mais ce n'était pas génial pour poster une réponse complète, alors j'ai fait ma propre réponse. Cela résout le problème d'obtention de "Aucune valeur". Vous devez obtenir le cadre actuel car je crois que lldb.frame est défini au moment de l'importation du module, il n'a donc pas le cadre actuel lorsque vous vous arrêtez à un point d'arrêt si vous chargez le module à partir de .lldbinit. L'autre version fonctionnerait si vous importiez ou rechargiez le script lorsque vous vous arrêtiez au point d'arrêt. La version ci-dessous devrait toujours fonctionner.

import lldb
import shlex

@lldb.command('parray', 'command script add -f parray.parray parray')
def parray(debugger, command, result, dict):

    target = debugger.GetSelectedTarget()
    process = target.GetProcess()
    thread = process.GetSelectedThread()
    frame = thread.GetSelectedFrame()

    args = shlex.split(command)
    if len(args) == 2:
        count = int(args[1])
        indices = range(count)
    Elif len(args) == 3:
        first = int(args[1])
        count = int(args[2])
        indices = range(first, first + count)
    else:
        print 'Usage: parray ARRAY [FIRST] COUNT'
        return

    for i in indices:
        print frame.GetValueForVariablePath(args[0] + "[" + str(i) + "]")
4
Dave Reed

Eh bien à ce stade, vous pouvez aussi bien écrire votre propre fonction C personnalisée et l'invoquer avec:

call (int)myprint(args)
1
Elektraglide

Pour inspecter les variables, vous pouvez utiliser le frame variable commande (fr v est le préfixe unique le plus court) qui a un -Z drapeau qui fait exactement ce que vous voulez:

(lldb) fr v buffer -Z5
(int64_t *) buffer = 0x000000010950c000 {
  (int64_t) [0] = 0
  (int64_t) [1] = 0
  (int64_t) [2] = 0
  (int64_t) [3] = 0
  (int64_t) [4] = 0
}

malheureusement, expression ne prend pas en charge cet indicateur

0
Holger