LLDB에서 배열보기 : Xcode 4.1의 GDB '@'연산자와 동일


79

포인터가 가리키는 요소 배열을보고 싶습니다. GDB에서는 '@'연산자를 사용하여 지정된 길이의 인공 배열로 지적 메모리를 처리하여 다음과 같이 수행 할 수 있습니다.

*pointer @ length

length보고 싶은 요소의 수는 어디에 있습니까 ?

위의 구문은 Xcode 4.1과 함께 제공되는 LLDB에서 작동하지 않습니다.

LLDB에서 위의 작업을 수행하는 방법이 있습니까?


1
거의 1 년이 지난 후에도 여전히 lldb에 이런 종류의 기능이없는 것 같습니다 (Xcode 4.3.3과 함께 LLDB-112.2를 사용하고 있습니다). 누군가가 유용한 해결 방법을 제시 할 수 있기를 바라며 현상금을 추가합니다 ( gdb로 돌아가는 것 외에는).
Paul R

답변:


141

lldb에는 두 가지 방법이 있습니다.

가장 일반적으로 parraya COUNT및 an 을 취하는 lldb 명령을 사용합니다 EXPRESSION. EXPRESSION평가되고 메모리에 대한 포인터가됩니다. 그러면 lldb는 COUNT해당 주소에 해당 유형의 항목 을 인쇄 합니다. 예 :

parray 10 ptr

어디 ptr유형 int *입니다.

또는 포인터를 배열에 대한 포인터로 캐스팅하여 수행 할 수 있습니다.

예를 들어를 가지고 있고 int* ptr이를 10 개의 정수 배열로 보려면 다음을 수행 할 수 있습니다.

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

표준 C 기능에만 의존하기 때문에이 방법은 플러그인이나 특수 설정없이 작동합니다. 마찬가지로 GDB 또는 CDB와 같은 다른 디버거에서도 작동하지만 배열 인쇄를위한 특수 구문도 있습니다.


4
이것은 좋은 대답입니다. 더 많은 찬성 투표를받을 가치가 있습니다. 커스텀 스크립팅이나 다른 것이 필요 없으며 구조체에서도 작동합니다.
Bill

22
첫 번째 데이터 요소 만 표시하는 포인터가있는 Xcode GUI를 사용하는 경우 다음을 수행하십시오. right click on data pointer > View value as... > Custom Type...In expression field put *(double(*)[10])value_type. 가리키는 10 개의 값이 출력됩니다. double 및 10을 원하는 유형 / 수량으로 수정할 수 있습니다.
Andrew Hundt 2015-08-08

GUI 관련 도움을 주신 @AndrewHundt에게 감사드립니다. 그게 바로 내가 원했던 것입니다.
weezma2004

@ weezma2004 댓글을 올릴 수 있다면 감사하겠습니다 :-) @ Siyuan Ren 아마도 정보가 귀하의 답변에 포함될 수 있습니까?
Andrew Hundt 2015 년

@AndrewHundt 완료. 지금까지 댓글을 찬성 할 수 있다는 사실조차 몰랐습니다. :)
weezma2004 2015 년

35

Xcode 8.0의 lldb부터 새로운 내장 parray 명령이 있습니다. 따라서 다음과 같이 말할 수 있습니다.

(lldb) parray <COUNT> <EXPRESSION>

의 결과가 가리키는 메모리를 표현식이 가리키는 유형 EXPRESSIONCOUNT요소 배열 로 인쇄합니다 .

카운트가 현재 프레임에서 사용 가능한 변수에 저장되면 다음을 수행 할 수 있습니다.

(lldb) parray `count_variable` pointer_to_malloced_array

이는 일반적인 lldb 기능입니다. 백틱으로 둘러싸인 lldb의 모든 명령 줄 인수는 정수를 반환하는 식으로 평가되고 명령 실행 전에 정수가 인수로 대체됩니다.


이 변수를 영구적으로 설정하는 방법이 있으므로 앱을 실행할 때마다 lldb 명령 프롬프트에이 변수를 다시 입력 할 필요가 없습니까?
MarcusJ 2017

무슨 뜻인지 잘 모르겠습니다. lldb 명령이있는 경우 축 어적으로 여러 번 사용 command alias하려면 바로 가기를 만드는 데 사용할 수 있습니다 .
Jim Ingham 2011

28

내가 찾은 유일한 방법은 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)

lldb에서 "parray"명령을 정의하십시오.

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

이제 "parray variable length "를 사용할 수 있습니다 .

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

2
팁 : 수정 후 스크립트를 다시로드해야하는 경우 "script reload (parray)"를 입력하십시오 ( libertypages.com/clarktech/?p=4303 참조 )
Raffi

@Raffi : 팁 감사합니다. 그리고 lldb / Python 정보에 대한 모든 링크는 가치가있는 경우 공식 문서가 여전히 제한되어 있습니다.
Martin R

1
@MartinR 내 실험에서 값 'a'는 스택 프레임에 존재하는 직선 포인터 여야하고 어떤 종류의 표현식이면 작동하지 않기 때문입니다. (예 : 포인터 캐스트, 오프셋 적용 등)
NoahR

내가 구조체 내부 배열을 인쇄하려고 할 때 내가 얻을AttributeError: 'NoneType' object has no attribute 'FindVariable'
fpg1503

15

Xcode 4.5.1 (지금 도움이 될 수도 있고 아닐 수도 있음)을 사용하면 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]

이 예에서는 '포인터'가 64 개의 부동 소수점 배열이라고 가정합니다. float pointer[64];


2
나는 거기에서 아무것도 이해하지 못하지만 작동하고 매우 도움이됩니다! 그런 훌륭한 lldb 트릭을 어디서 배우나요?
나단

지금부터 인쇄 된 모든 float *가 64 개 요소의 배열로 표시 되지 않을까요 ?
uliwitness

네, 그렇습니다. 더 이상 필요하지 않은 경우 유형 요약을 삭제할 수 있습니다. 첫 번째 값만 보는 것보다 여전히 낫습니다.
davidA

13

Martin R 답변으로 시작하여 다음과 같이 개선했습니다.

  1. 포인터가 단순 변수가 아닌 경우, 예 :

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

    그런 다음 "parray a.at 5"가 실패합니다.

    "FindVariable"을 "GetValueForVariablePath"로 바꾸어이 문제를 해결했습니다.

  2. 이제 배열의 요소가 집계이면 어떻게됩니까?

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

    그런 다음 "parray a.at 5"는 다음을 인쇄합니다. a.at-> x, a.at-> y, a.at [2], a.at [3], a.at [4] GetChildAtIndex ()가 멤버를 반환하기 때문입니다. 집계의.

    "a.at"를 확인한 다음 그 자식을 검색하는 대신 루프 내부에서 "a.at"+ "["+ str (i) + "]"를 해결하여이 문제를 해결했습니다.

  3. 선택적인 "첫 번째"인수 (사용 : parray [FIRST] COUNT)를 추가했습니다. 이는 많은 수의 요소가있을 때 유용합니다.

  4. init에서 "command script add -f parray.parray parray"를 수행했습니다.

다음은 수정 된 버전입니다.

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')

최신 버전 lldb(또는 Python)에서는 첫 번째 할당과 계산이 별도의 줄에 있어야합니다. 그 외에도 이것은 훌륭하게 작동합니다! 감사합니다!
Kaelin Colclasure 2013 년

GetValueForVariablePath 팁 덕분에 Martin R을 특정 사례에 적용하기 위해 한 시간 동안 고군분투했습니다!
Raffi 2013-09-18

큰 시도와 매우 유용합니다. 대부분의 포인터 표현식의 난에 관심이 GetValueForVariablePath반환됩니다 No Value. Xcode 5.0에서 lldb-300.2.47을 사용하고 있습니다. 를 들어 int array[8], parry array 8반환 No Value동안 8 번 print array[0]작품은 예상대로.
NoahR

1
문제는 lldb.frame이 모듈 가져 오기에 설정되어 있으므로 대신 현재 프레임을 가져 오는 명령이 필요하다는 것입니다. target = debugger.GetSelectedTarget () process = target.GetProcess () thread = process.GetSelectedThread () frame = thread.GetSelectedFrame () 다음 lldb.frame.GetValueForVariablePath 대신 frame.GetValueForVariablePath 사용
Dave Reed

@DaveReed의 위 의견은 문제의 일부를 다루었습니다. 간단한 포인터 사용이 작동하기 시작했습니다. (현재 프레임의 포인터 변수, 유형 변환 또는 산술 없음). 내가 밖으로 변경했습니다, 그래서 나는,보다 정교한 표현을하고 싶지 GetValueForVariablePath위해 EvaluateExpression나는 아직도보고 있었기 때문에 No value. 이제 다음과 같은 포인터 표현식이 작동합니다 parray ((double*)sourcePointer+1) 5.. 두 함수의 반환 유형은 API 문서에 따라 동일하므로 EvaluateExpression더 나은 방법으로 보입니다.
NoahR

12

아직 지원되지 않는 것 같습니다.

메모리 읽기 기능 (메모리 읽기 / x)을 사용할 수 있습니다.

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

그 포인터에서 float를 10 번 인쇄합니다. 이것은 gdb의 @과 동일한 기능이어야합니다.


2
백틱을 사용하여 포인터 표현식을 평가할 수 있습니다. 예 :(lldb) memory read -ff -c10 `test`
pmdj

1
이것이 받아 들여진 대답이어야합니다! 간편하고 즉시 사용할 수 있습니다
wxs

1
그리고 타이핑을 절약하기 위해x/10f test
wardw

5

댓글을 달아 보려고했는데 전체 답변을 올리기 엔 좋지 않아서 직접 답변을했습니다. 이것은 "가치 없음"을 얻는 문제를 해결합니다. lldbinit에서 모듈을로드하는 경우 중단 점에서 멈출 때 lldb.frame이 모듈 가져 오기 시간에 설정되어 있다고 생각하므로 현재 프레임을 가져와야합니다. 중단 점에서 중지했을 때 스크립트를 가져 오거나 다시로드하면 다른 버전이 작동합니다. 아래 버전은 항상 작동합니다.

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) + "]")

죄송합니다. 답변을보기 전에 댓글에 댓글을 달았습니다. 이를 통해 간단한 포인터 사용이 작동합니다. (현재 프레임의 포인터 변수, 유형 변환 또는 산술 없음). 좀 더 정교한 식을 수행하고 싶기 때문에 여전히 No value가 표시 되었기 때문에 EvaluateExpression에 대해 GetValueForVariablePath를 변경했습니다. 이제 다음과 같은 포인터 표현식이 작동합니다. parray ((double *) sourcePointer + 1) 5. 두 함수의 반환 유형은 API 문서에 따라 동일하므로 EvaluateExpression이 더 나은 방법으로 보입니다. 동의하십니까?
NoahR

한 가지 차이점은의 출력이 EvaluateExpressionlldb 변수에 할당되고 배열 인덱스가 인쇄되지 않는다는 것입니다. 그래서, 출력과 같은 라인은 다음과 같습니다(double) $68 = 0
NoahR

1
@ dave-reed,이 스크립트를 lldb에 설치하거나 첨부하는 방법은 무엇입니까? 어딘가에 저장 한 다음 .lldbinit에 추가해야합니까?
Shmidt

3

변수를 검사하려면 원하는 작업을 정확히 수행 하는 플래그 가있는 frame variable명령 ( fr v가장 짧은 고유 접두사)을 사용할 수 있습니다 -Z.

(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
}

안타깝게도 expression해당 플래그를 지원하지 않습니다.


2

이 시점에서 사용자 정의 C 함수를 작성하고 다음과 같이 호출 할 수도 있습니다.

call (int)myprint(args)

실제로는 아닙니다. 프로그램을 다시 시작하고 오류를 재현하지 않고도 LLDB 세션에 실시간으로 Python 버전을 추가 할 수 있습니다.
Bill
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.